/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tuwien.big.memory.controller;

import at.ac.tuwien.big.ewa.memory.MemoryCard;
import javax.faces.bean.ManagedBean;
import at.ac.tuwien.big.ewa.memory.MemoryGame;
import at.ac.tuwien.big.ewa.memory.MemoryPlayer;
import at.ac.tuwien.big.highscore.webservice.HighScoreResultRequest;
import at.ac.tuwien.big.highscore.webservice.HighScoreServiceImplService;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.faces.bean.NoneScoped;
import tuwien.big.memory.entities.Player;

import net.roarsoftware.lastfm.*;


/**
 *
 * @author Dieter
 */
@ManagedBean(name = "mc")
@NoneScoped
public class MemoryControl {
    
    private Player player1;
    private Player player2;
    private Player currentplayer;

    private MemoryPlayer mplayer1;
    private MemoryPlayer mplayer2;

    private boolean readytoplay = false;

    MemoryGame mgame = null;
    int stacksize = 0;
    int trycounter = 0;
    private String cardpath = "img/card_images/card";
    private String cardpathext = ".jpg";
    private String backcardpath = "./resources/img/card_background.png";
    private String genre = "rock";
    private Collection<Artist> topArtists;
    private HashMap<Player, Integer> highscore;

    /** Creates a new instance of MemoryControl */
    public MemoryControl() {
    }

    public MemoryControl(Player p1, Player p2) {
        player1 = p1;
        this.stacksize = player1.getStacksize();
        player2 = p2;
        currentplayer = p1;
        init();
        
    }

    public boolean checkHighscore(Player player) {
        
        if( this.highscore.get(player) > 0 )
            return true;
        else
            return false;
    }

    public String getHighscore(Player player) {

        int result = 0;

        // highscore already submitted
        if( this.highscore.get(player) != 0 ) {
            if( this.highscore.get(player) == -1 )
                return "";
            else
                return "" + this.highscore.get(player);
        }
        else {
            HighScoreServiceImplService service = new HighScoreServiceImplService();
            HighScoreResultRequest request = new HighScoreResultRequest();

            int playTime;
            int pairsCount;

            // get spend time and uncovered pairs
            if( this.player1.equals(player) ){
                playTime = (int) mgame.getSpentTime(mplayer1) / 1000;
                pairsCount = mplayer1.getUncoveredMatchingPairsCount();
            }
            else {
                playTime = (int) mgame.getSpentTime(mplayer2) / 1000;
                pairsCount = mplayer2.getUncoveredMatchingPairsCount();
            }

            // calculate the result
            if( pairsCount == 0 ) {
                this.highscore.remove(player);
                this.highscore.put(player, -1);
                return "-";
            }
            else if ( playTime == 0 ) {
                this.highscore.remove(player);
                this.highscore.put(player, -1);
                return "-";
            }
            else {
                result = (int) playTime / pairsCount;
                this.highscore.remove(player);

                // prepare the request
                request.setAuthenticationToken("ewa4eva");
                request.setGameMode((int) Math.sqrt(stacksize) + "x" + (int) Math.sqrt(stacksize));
                request.setUsername(player.getName());
                request.setResult(result);

                // try to submit the result
                try {
                    result = service.getHighScoreServiceImplPort().publishHighScoreResult(request);
                } catch (Exception e) {
                    e.printStackTrace();
                    result = -1;
                }

                this.highscore.remove(player);
                this.highscore.put(player, result);

                return "" + result;
            }
        }
    }

    public Player getOpponent(Player p)
    {
        if(player1 == p)
            return player2;
        else
            return player1;
    }

    public boolean isTurn(Player p)
    {
        if(p == currentplayer)
            return true;
        else
            return false;
    }

    /**
     * @return the player1
     */
    public Player getPlayer1() {
        return player1;
    }

    /**
     * @return the player2
     */
    public Player getPlayer2() {
        return player2;
    }

    /**
     * @param player1 the player1 to set
     */
    public void setPlayer1(Player player1) {
        this.player1 = player1;
        if(player2 != null && player1 != null)
            readytoplay = true;
        init();
    }

    /**
     * @param player2 the player2 to set
     */
    public void setPlayer2(Player player2) {
        this.player2 = player2;
        if(player2 != null && player1 != null)
            readytoplay = true;
        init();
    }

    /**
     * @return the readytoplay
     */
    public boolean isReadytoplay() {
        return readytoplay;
    }

    /**
     * @param readytoplay the readytoplay to set
     */
    public void setReadytoplay(boolean readytoplay) {
        this.readytoplay = readytoplay;
    }

    /**
     * @return the currentplayer
     */
    public Player getCurrentplayer() {
        return currentplayer;
    }

    public String startGame() {
        return "memory";
    }

    public void init() {
        if(readytoplay) {
            String key = "b25b959554ed76058ac220b7b2e0a026"; //this is the key used in the last.fm API examples online.

            this.genre = this.player1.getGenre();

            this.topArtists = new ArrayList(Tag.getTopArtists(this.genre, key)).subList(0, 3);
            List<String> cardlist = new ArrayList<String>();

            for (int i = 1; i <= (stacksize / 2); i++) {
                Album temp = (new ArrayList<Album>(Tag.getTopAlbums(this.genre, key))).get(i);
                cardlist.add(temp.getImageURL(ImageSize.LARGE));
            }
            
            List<MemoryPlayer> playerlist = new ArrayList<MemoryPlayer>();
            mplayer1 = new MemoryPlayer(player1.getName());
            mplayer2 = new MemoryPlayer(player2.getName());
            playerlist.add(mplayer1);
            playerlist.add(mplayer2);        

            mgame = new MemoryGame(playerlist, cardlist);
             if(mgame.getCurrentPlayer().getName().compareTo(player1.getName())==0) {
                currentplayer = player1;
            }
            else {
                currentplayer = player2;
            }

            this.highscore = new HashMap<Player, Integer>();
            this.highscore.put(this.player1, 0);
            this.highscore.put(this.player2, 0);
                       
        }
    }

    public MemoryPlayer getCurrentPlayer() {
        return mgame.getCurrentPlayer();
    }

    public void changeshow(int row, int column) {
        if (mgame.getCardByIndex(row, column).getCurrentState() == MemoryCard.CardState.COVERED) {
            mgame.uncover(mgame.getCurrentPlayer(), mgame.getCardByIndex(row, column));
           
            if(mgame.getCurrentPlayer().getName().compareTo(player1.getName())==0) {
                currentplayer = player1;                
            }
            else {
                currentplayer = player2;
            }
        }
    }

    public String getPlayerTime(Player p) {

        long millisec;
        if(mplayer1.getName().compareTo(p.getName())==0) {
            millisec = mgame.getSpentTime(mplayer1);
        }
        else {
            millisec = mgame.getSpentTime(mplayer2);
        }

        SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
        return sdf.format(new Date(millisec));
    }

    public MemoryPlayer getMemoryPlayer(Player p) {
        if(mplayer1.getName().compareTo(p.getName())==0) {
            return mplayer1;
        }
        else {
            return mplayer2;
        }
    }

    public String getCoveredPairsCount() {
        return Integer.toString((stacksize / 2 - mplayer1.getUncoveredMatchingPairsCount() - mplayer2.getUncoveredMatchingPairsCount()));
    }

    public boolean isGameOver() {
        return mgame.isGameOver();
    }

    /**
     * @return the cards
     */
    public ArrayList<ArrayList> getCards() {
        ArrayList<ArrayList> cards = new ArrayList<ArrayList>();
        ArrayList<MemoryCard> row = null;

        for (int i = 0; i < mgame.getTable().length; i++) {
            row = new ArrayList<MemoryCard>();
            cards.add(row);

            for (int j = 0; j < mgame.getTable()[i].length; j++) {
                row.add(mgame.getTable()[i][j]);
            }
        }

        return cards;
    }

    /**
     * @return the cardpath
     */
    public String getCardpath() {
        return cardpath;
    }

    /**
     * @param cardpath the cardpath to set
     */
    public void setCardpath(String cardpath) {
        this.cardpath = cardpath;
    }

    /**
     * @return the cardpathext
     */
    public String getCardpathext() {
        return cardpathext;
    }

    /**
     * @param cardpathext the cardpathext to set
     */
    public void setCardpathext(String cardpathext) {
        this.cardpathext = cardpathext;
    }

    /**
     * @return the backcardpath
     */
    public String getBackcardpath() {
        return backcardpath;
    }

    /**
     * @param backcardpath the backcardpath to set
     */
    public void setBackcardpath(String backcardpath) {
        this.backcardpath = backcardpath;
    }

    public Collection<Artist> getTopArtists() {
        return this.topArtists;
    }

    public void setTopArtists(Collection<Artist> topArtists) {
        this.topArtists = topArtists;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public MemoryPlayer getMplayer1() {
        return mplayer1;
    }

    public void setMplayer1(MemoryPlayer mplayer1) {
        this.mplayer1 = mplayer1;
    }

    public MemoryPlayer getMplayer2() {
        return mplayer2;
    }

    public void setMplayer2(MemoryPlayer mplayer2) {
        this.mplayer2 = mplayer2;
    }
}
